﻿using System;
using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;

namespace SharpGL.SceneGraph
{
    /// <summary>
    /// A plane.
    /// </summary>
    [DataContract()]
    public class Plane : INotifyPropertyChanged
    {
        #region Private Fields

        /// <summary>
        /// The position.
        /// </summary>
        [DataMember()]
        private Point3D position = new Point3D(0, 0, 0);

        /// <summary>
        /// The normal.
        /// </summary>
        [DataMember()]
        private Vector3D normal = new Vector3D(0, 0, 0);

        /// <summary>
        /// The equation.
        /// </summary>
        [DataMember()]
        private float[] equation = new float[4]; // ax + by + cz + d = 0.

        #endregion Private Fields

        #region Protected Methods

        /// <summary>
        /// Call this function to do the PropertyChanged event.
        /// </summary>
        protected void NotifyPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion Protected Methods

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Plane"/> class.
        /// </summary>
        public Plane()
        {
        }

        #endregion Constructors

        #region Public Methods

        /// <summary>
        /// This finds out if a point is in front of, behind, or on this plane.
        /// </summary>
        /// <param name="point">The point to classify.</param>
        /// <returns>
        /// Less than 0 if behind, 0 if on, Greater than 0 if in front.
        /// </returns>
        public float ClassifyPoint(Point3D point)
        {
            //	(X-P)*N = 0. Where, X is a point to test, P is a point
            //	on the plane, and N is the normal to the plane.

            return Vector3D.DotProduct(normal, (Vector3D)point);
        }

        #endregion Public Methods

        #region Public Events

        [Description("Called when properties has been changed."), Category("SharpGL")]
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion Public Events

        #region Public Properties

        /// <summary>
        /// The position.
        /// </summary>
        public Point3D Position
        {
            get { return position; }
            set
            {
                if (position != value)
                {
                    position = value;

                    NotifyPropertyChanged("Position");
                }
            }
        }

        /// <summary>
        /// The normal.
        /// </summary>
        public Vector3D Normal
        {
            get { return normal; }
            set
            {
                if (normal != value)
                {
                    normal = value;

                    NotifyPropertyChanged("Normal");
                }
            }
        }

        /// <summary>
        /// The equation.
        /// </summary>
        public float[] Equation
        {
            get { return equation; }
            set
            {
                if (equation != value)
                {
                    equation = value;

                    NotifyPropertyChanged("Equation");
                }
            }
        }

        #endregion Public Properties
    }
}